/*
 * Copyright (c) 2025 Huawei Device, Inc. Ltd. and <马弓手>.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


#include "SocialSharing.h"
#include "ConnPool.h"
#include "FileCache.h"
#include "MemPool.h"
#include "cJSON.h"
#include "HttpUrl.h"
#include <filemanagement/file_uri/oh_file_uri.h>

REGISTER_PLUGIN_CLASS(SocialSharing)

void SocialSharing::pluginInitialize()
{
    m_vecInvalidPackageName.push_back("com.facebook.katana");          // Facebook
    m_vecInvalidPackageName.push_back("com.facebook.orca");            // Facebook Messenger
    m_vecInvalidPackageName.push_back("com.twitter.android");          // Twitter
    m_vecInvalidPackageName.push_back("com.whatsapp");                 // WhatsApp
    m_vecInvalidPackageName.push_back("com.instagram.android");        // Instagram
    m_vecInvalidPackageName.push_back("com.snapchat.android");         // Snapchat
    m_vecInvalidPackageName.push_back("com.linkedin.android");         // LinkedIn
    m_vecInvalidPackageName.push_back("com.pinterest");                // Pinterest
    m_vecInvalidPackageName.push_back("com.tumblr");                   // Tumblr
    m_vecInvalidPackageName.push_back("com.reddit.frontpage");         // Reddit
    m_vecInvalidPackageName.push_back("org.telegram.messenger");       // Telegram
    m_vecInvalidPackageName.push_back("com.viber.voip");               // Viber
    m_vecInvalidPackageName.push_back("com.skype.raider");             // Skype
    m_vecInvalidPackageName.push_back("kik.android");                  // Kik
    m_vecInvalidPackageName.push_back("com.discord");                  // Discord
    
    m_mapMime["3gp"] = "video/3gpp";
    m_mapMime["apk"] = "application/vnd.android.package-archive";
    m_mapMime["asf"] = "video/x-ms-asf";
    m_mapMime["avi"] = "video/x-msvideo";
    m_mapMime["bin"] = "application/octet-stream";
    m_mapMime["bmp"] = "image/bmp";
    m_mapMime["c"] =   "text/plain";
    m_mapMime["class"] = "application/octet-stream";
    m_mapMime["conf"] = "text/plain";
    m_mapMime["cpp"] = "text/plain";
    m_mapMime["doc"] = "application/msword";
    m_mapMime["docx"] = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
    m_mapMime["xls"] = "application/vnd.ms-excel";
    m_mapMime["xlsx"] = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
    m_mapMime["exe"] = "application/octet-stream";
    m_mapMime["gif"] = "image/gif";
    m_mapMime["gtar"] = "application/x-gtar";
    m_mapMime["gz"] =  "application/x-gzip";
    m_mapMime["h"] =   "text/plain";
    m_mapMime["htm"] = "text/html";
    m_mapMime["html"] = "text/html";
    m_mapMime["jar"] = "application/java-archive";
    m_mapMime["java"] = "text/plain";
    m_mapMime["jpeg"] = "image/jpeg";
    m_mapMime["jpg"] = "image/jpeg";
    m_mapMime["js"] =  "application/x-javascript";
    m_mapMime["log"] = "text/plain";
    m_mapMime["m3u"] = "audio/x-mpegurl";
    m_mapMime["m4a"] = "audio/mp4a-latm";
    m_mapMime["m4b"] = "audio/mp4a-latm";
    m_mapMime["m4p"] = "audio/mp4a-latm";
    m_mapMime["m4u"] = "video/vnd.mpegurl";
    m_mapMime["m4v"] = "video/x-m4v";
    m_mapMime["mov"] = "video/quicktime";
    m_mapMime["mp2"] = "audio/x-mpeg";
    m_mapMime["mp3"] = "audio/x-mpeg";
    m_mapMime["mp4"] = "video/mp4";
    m_mapMime["mpc"] = "application/vnd.mpohun.certificate";
    m_mapMime["mpe"] = "video/mpeg";
    m_mapMime["mpeg"] = "video/mpeg";
    m_mapMime["mpg"] = "video/mpeg";
    m_mapMime["mpg4"] = "video/mp4";
    m_mapMime["mpga"] ="audio/mpeg";
    m_mapMime["msg"] = "application/vnd.ms-outlook";
    m_mapMime["ogg"] = "audio/ogg";
    m_mapMime["pdf"] = "application/pdf";
    m_mapMime["png"] = "image/png";
    m_mapMime["pps"] = "application/vnd.ms-powerpoint";
    m_mapMime["ppt"] = "application/vnd.ms-powerpoint";
    m_mapMime["pptx"] = "application/vnd.openxmlformats-officedocument.presentationml.presentation";
    m_mapMime["prop"] = "text/plain";
    m_mapMime["rc"] =  "text/plain";
    m_mapMime["rmvb"] = "audio/x-pn-realaudio";
    m_mapMime["rtf"] = "application/rtf";
    m_mapMime["sh"] =  "text/plain";
    m_mapMime["tar"] = "application/x-tar";
    m_mapMime["tgz"] = "application/x-compressed";
    m_mapMime["txt"] = "text/plain";
    m_mapMime["wav"] = "audio/x-wav";
    m_mapMime["wma"] = "audio/x-ms-wma";
    m_mapMime["wmv"] = "audio/x-ms-wmv";
    m_mapMime["wps"] = "application/vnd.ms-works";
    m_mapMime["xml"] = "text/plain";
    m_mapMime["z"] =   "application/x-compress";
    m_mapMime["zip"] = "application/x-zip-compressed";
}

bool SocialSharing::execute(const string&  action, cJSON* args, CallbackContext cbc)
{
    if(action == "available") {
        cbc.success();
    }
    
    if(action == "share") {
        m_cbc = cbc;
        CordovaArgs cordovaArgs(args);
        string msg = cordovaArgs.getString(0);
        string subject = cordovaArgs.getString(1);
        cJSON* pFiles = cordovaArgs.getJSONArray(2);
        string url = cordovaArgs.getString(3);
        string appPackageName = "";
        string chooserTitle = "";
        string strArgs;
        if(getShareInfo(msg,subject,pFiles,url,appPackageName, chooserTitle,false,strArgs)) {
            executeArkTsAsync("./SocialSharing/SocialSharing/SocialSharing", 0, strArgs.c_str(), "SocialSharing", cbc);
        } else {
            cbc.error("Not supported");
        }
    }
    
    if(action == "shareWithOptions") {
        m_cbc = cbc;
        cJSON* pObj = cJSON_GetArrayItem(args, 0);
        if(pObj != nullptr) {
            string msg = "";
            cJSON* pMsg = cJSON_GetObjectItem(pObj, "message");
            if(pMsg != nullptr && pMsg->type == cJSON_String) {
                msg = pMsg->valuestring;
            }
            string subject = "";
            cJSON* pSubject = cJSON_GetObjectItem(pObj, "subject");
            if(pSubject != nullptr && pSubject->type == cJSON_String) {
                subject = pSubject->valuestring;
            }
            cJSON* pFiles = cJSON_GetObjectItem(pObj, "files");
            string url = "";
            cJSON* pUrl = cJSON_GetObjectItem(pObj, "url");
            if(pUrl != nullptr && pUrl->type == cJSON_String) {
                url = pUrl->valuestring;
            }
            string appPackageName = "";
            cJSON* pPackageName = cJSON_GetObjectItem(pObj, "appPackageName");
            if(pPackageName != nullptr && pPackageName->type == cJSON_String) {
                appPackageName = pPackageName->valuestring;
            }
            string chooserTitle = "";
            cJSON* pChooserTitle = cJSON_GetObjectItem(pObj, "chooserTitle");
            if(pChooserTitle != nullptr && pChooserTitle->type == cJSON_String) {
                chooserTitle = pChooserTitle->valuestring;
            }
            string strArgs;
            if(getShareInfo(msg,subject,pFiles,url,appPackageName, chooserTitle,false, strArgs)) {
                executeArkTsAsync("./SocialSharing/SocialSharing/SocialSharing", 0, strArgs.c_str(), "SocialSharing", cbc);
            } else {
                cbc.error("Not supported");
            }
        }
    }
    if(action == "canShareVia") {
        m_cbc = cbc;
        CordovaArgs cordovaArgs(args);
        string msg = cordovaArgs.getString(0);
        string subject = cordovaArgs.getString(1);
        cJSON* pFiles = cordovaArgs.getJSONArray(2);
        string url = cordovaArgs.getString(3);
        string appPackageName = cordovaArgs.getString(4);
        string chooserTitle = cordovaArgs.getString(5);
        string strArgs;
        if(getShareInfo(msg,subject,pFiles,url,appPackageName, chooserTitle,true, strArgs)) {
            executeArkTsAsync("./SocialSharing/SocialSharing/SocialSharing", 0, strArgs.c_str(), "SocialSharing", cbc);
        } else {
            cbc.error("Not supported");
        }
    }
    if(action == "canShareViaEmail") {
         cbc.success();//鸿蒙系统内置有邮件系统，完全支持，无需判断
    }
    if(action == "shareVia") {
        m_cbc = cbc;
        CordovaArgs cordovaArgs(args);
        string msg = cordovaArgs.getString(0);
        string subject = cordovaArgs.getString(1);
        cJSON* pFiles = cordovaArgs.getJSONArray(2);
        string url = cordovaArgs.getString(3);
        string appPackageName = cordovaArgs.getString(4);
        string chooserTitle = cordovaArgs.getString(5);
        string strArgs;
        if(getShareInfo(msg,subject,pFiles,url,appPackageName,chooserTitle,false, strArgs)) {
            executeArkTsAsync("./SocialSharing/SocialSharing/SocialSharing", 0, strArgs.c_str(), "SocialSharing", cbc);
        } else {
            cbc.error("Not supported");
        }
    }
    if(action == "shareViaTwitter") {
        cbc.error("Not supported");
    }
    if(action == "shareViaFacebook") {
        cbc.error("Not supported");
    }
    if(action == "shareViaFacebookWithPasteMessageHint") {
        cbc.error("Not supported");
    }
    if(action == "shareViaWhatsApp") {
        cbc.error("Not supported");
    }
    if(action == "shareViaInstagram") {
        cbc.error("Not supported");
    }
    if(action == "shareViaSMS") {
         m_cbc = cbc;
        CordovaArgs cordovaArgs(args);
        cJSON* pObject = cordovaArgs.getJSONObject(0);
        string phones = cordovaArgs.getString(1);
        cJSON* pMessage = cJSON_GetObjectItem(pObject, "message");
        string message = "";
        if(pMessage != nullptr && pMessage->type == cJSON_String) {
            message = pMessage->valuestring;
        }
        cJSON* pSubject = cJSON_GetObjectItem(pObject, "subject");
        string subject = "";
        if(pSubject != nullptr && pSubject->type == cJSON_String) {
            subject = pSubject->valuestring;
        }
        cJSON* pImage = cJSON_GetObjectItem(pObject, "image");
        string strImage;
        if(pImage != nullptr && pImage->type == cJSON_String) {
            strImage = pImage->valuestring;
        }
        string strInfo;
        if(getSmsInfo(phones, message, subject, strImage, strInfo)) {
            executeArkTsAsync("./SocialSharing/SocialSharing/SocialSharing", 1, strInfo.c_str(), "SocialSharing", cbc);
        }
    }
    if(action == "shareViaEmail") {
        m_cbc = cbc;
        CordovaArgs cordovaArgs(args);
        string msg = cordovaArgs.getString(0);
        string subject = cordovaArgs.getString(1);
        cJSON* pTo = cordovaArgs.getJSONArray(2);
        string strTo;
        if(pTo != nullptr) {
            strTo = getInfo(pTo);
        }
        cJSON* pCc = cordovaArgs.getJSONArray(3);
        string strCc;
        if(pCc != nullptr) {strCc = getInfo(pCc);
        }
        cJSON* pBcc = cordovaArgs.getJSONArray(4);
        string strBcc;
        if(pBcc != nullptr) {
            strBcc = getInfo(pBcc);
        }
        cJSON* pFiles = cordovaArgs.getJSONArray(5);
        string strInfo;
        if(getEmailInfo(msg,subject, pFiles, strTo, strCc,strBcc,false,strInfo)) {
             executeArkTsAsync("./SocialSharing/SocialSharing/SocialSharing", 2, strInfo.c_str(), "SocialSharing", cbc);
        }
    }
    
    if(action == "onArKTsResult") {
        return onArKTsResult(args);
    }
    return true;
}

bool SocialSharing::onArKTsResult(cJSON* args)
{
   cJSON* content = cJSON_GetObjectItem(args, "content");
    string action = "";
    if(content != NULL) {
        action = content->valuestring;
    }
    if(action == "share" || action == "shareWithOptions") {
         cJSON* json = cJSON_GetObjectItem(args, "result");
        if(json != NULL && json->type == cJSON_Array) {
            int count = cJSON_GetArraySize(json);
            if(count > 0) {
                string strResult = cJSON_GetArrayItem(json, 0)->valuestring;
                if(strResult == "true") {
                    PluginResult pluginResult(PluginResult::OK, true);
                    m_cbc.sendPluginResult(pluginResult);
                } else {
                    //这里返回和android不一致，因api12没有监听分享成功的api
                   PluginResult pluginResult(PluginResult::ERROR, false);
                    m_cbc.sendPluginResult(pluginResult);
                }
            }
        }
    }
    if(action == "canShareVia" || action == "shareVia" || action == "shareViaSMS" || action == "shareViaEmail") {
        cJSON* json = cJSON_GetObjectItem(args, "result");
        if(json != NULL && json->type == cJSON_Array) {
            int count = cJSON_GetArraySize(json);
            if(count > 0) {
                string strResult = cJSON_GetArrayItem(json, 0)->valuestring;
                if(strResult == "true") {
                    m_cbc.success();
                } else {
                    m_cbc.error("Not supported");
                }
            }
        }
    }
    return true;
}

string SocialSharing::getInfo(cJSON* pArray)
{
    string strRet = "";
    if(pArray == nullptr) {
        return strRet;
    }
    int nCount = cJSON_GetArraySize(pArray);
    for(int i=0; i<nCount; i++) {
        if(!strRet.empty()) {
            strRet += ",";
        }
        cJSON* pItem = cJSON_GetArrayItem(pArray, i);
        if(pItem != nullptr && pItem->type == cJSON_String) {
            strRet += FileCache::urlEncode(pItem->valuestring);
        }
    }
    return strRet;
}

bool SocialSharing::getShareInfo(const string& strMessage, const string& strSubject, cJSON* pArray, const string& strUrl, const string& strPackageName, const string& strChooserTitle, const bool isPeek, string& strInfo)
{
    cJSON* pJson = cJSON_CreateObject();
    cJSON_AddStringToObject(pJson, "message", strMessage.c_str());
    cJSON_AddStringToObject(pJson, "subject", strSubject.c_str());
    if(pArray != nullptr) {
        string strFiles = getInfo(pArray);
        vector<string> vecFiles;
        HttpUrl::SplitString(strFiles, ",", vecFiles);
        strFiles = "";
        string strMimeTypes = "";
        for(int i=0; i<vecFiles.size(); i++) {
            //分享的是在线内容，作为链接分享，无论在线内容是视频或者图片，都下载到本地
            if(vecFiles[i].find("http") == 0) { 
                string strFilePath;
                if(downloadFile(vecFiles[i], strFilePath)) {
                    vecFiles[i] = strFilePath;
                } else {
                    vecFiles[i] = "";
                }
            }
            if(vecFiles[i].find("data:") == 0) {//base64字符串，在js侧使用 new Array("data:...");鸿蒙拆分为了两个数组，字符串在下一个数字，android是一个数组，这里要采用兼容性写法
                string strBase64Data;
                if(vecFiles[i].length() > vecFiles[i].find("base64")+6) {
                    //base64字符在当前数组元素中
                    strBase64Data = vecFiles[i].substr(vecFiles[i].find("base64")+7);
                } else {
                    //base64字符在下一个数组元素中
                    if(i+1 < vecFiles.size()) {
                        strBase64Data = vecFiles[i+1];
                        vecFiles[i+1] = "";
                    }
                }
                if(!strBase64Data.empty()) {
                    string strFileName = HttpUrl::generateMD5(strBase64Data)+FileCache::getImageType(strBase64Data);
                    string strTarget = Application::g_databaseDir.substr(0, Application::g_databaseDir.find("database")-1)+"/base/cache/"+strFileName;
                    if(!FileCache::IsFile(strTarget, "")) {
                        string str = FileCache::urlDecode(strBase64Data);
                        int nLength = str.length();
                        char* pBuf = CBase64::decode(str.c_str(), nLength);
                        if(pBuf != nullptr) {
                            FileCache::writeFile(strTarget, pBuf, nLength);
                            vecFiles[i] = strTarget;
                        } else {
                            vecFiles[i] = "";
                        }
                    } else {
                        vecFiles[i] = strTarget;
                    }
                }
            }
            if(!vecFiles[i].empty()) {
                char* result = nullptr;
                string mimeType = getMIMEType(vecFiles[i]);
                FileManagement_ErrCode errCode = OH_FileUri_GetUriFromPath(vecFiles[i].c_str(),vecFiles[i].length(), &result);
                if(errCode == ERR_OK) {
                    if(!strFiles.empty()) {
                        strFiles += ",";
                        strMimeTypes += ",";
                    }
                    strFiles += result;
                    strMimeTypes += mimeType;
                }
                if(result != nullptr) {
                    free(result);
                }
           }
        }
        cJSON_AddStringToObject(pJson, "files", strFiles.c_str());
        cJSON_AddStringToObject(pJson, "mimeTypes", strMimeTypes.c_str());
    }
    
    cJSON_AddStringToObject(pJson, "url", strUrl.c_str());
    cJSON_AddStringToObject(pJson, "packageName", strPackageName.c_str());
    cJSON_AddBoolToObject(pJson, "peek", isPeek);
    cJSON_AddStringToObject(pJson, "chooserTitle", strChooserTitle.c_str());
    char* pStr = cJSON_Print(pJson);
    strInfo = pStr;
    free(pStr);
    cJSON_Delete(pJson);
    if(find(m_vecInvalidPackageName.begin(), m_vecInvalidPackageName.end(), strPackageName) != m_vecInvalidPackageName.end()) {
        return false;
    }
    return true;
}

bool SocialSharing::getEmailInfo(const string& strMessage, const string& strSubject, cJSON* pArray, const string& strTo, const string& strCc, const string& strBcc,  const bool isPeek, string& strInfo)
{
    cJSON* pJson = cJSON_CreateObject();
    cJSON_AddStringToObject(pJson, "message", strMessage.c_str());
    cJSON_AddStringToObject(pJson, "subject", strSubject.c_str());
    if(pArray != nullptr) {
        string strFiles = getInfo(pArray);
        vector<string> vecFiles;
        HttpUrl::SplitString(strFiles, ",", vecFiles);
        strFiles = "";
        string strMimeTypes = "";
        for(int i=0; i<vecFiles.size(); i++) {
            //分享的是在线内容，作为链接分享，无论在线内容是视频或者图片，都下载到本地
            if(vecFiles[i].find("http") == 0) { 
                string strFilePath;
                if(downloadFile(vecFiles[i], strFilePath)) {
                    vecFiles[i] = strFilePath;
                } else {
                    vecFiles[i] = "";
                }
            }
            if(vecFiles[i].find("data:") == 0) {//base64字符串，在js侧使用 new Array("data:...");鸿蒙拆分为了两个数组，字符串在下一个数字，android是一个数组，这里要采用兼容性写法
                string strBase64Data;
                if(vecFiles[i].length() > vecFiles[i].find("base64")+6) {
                    //base64字符在当前数组元素中
                    strBase64Data = vecFiles[i].substr(vecFiles[i].find("base64")+7);
                } else {
                    //base64字符在下一个数组元素中
                    if(i+1 < vecFiles.size()) {
                        strBase64Data = vecFiles[i+1];
                        vecFiles[i+1] = "";
                    }
                }
                if(!strBase64Data.empty()) {
                    string strFileName = HttpUrl::generateMD5(strBase64Data)+FileCache::getImageType(strBase64Data);
                    string strTarget = Application::g_databaseDir.substr(0, Application::g_databaseDir.find("database")-1)+"/base/"+strFileName;
                    if(!FileCache::IsFile(strTarget, "")) {
                        string str = FileCache::urlDecode(strBase64Data);
                        int nLength = str.length();
                        char* pBuf = CBase64::decode(str.c_str(), nLength);
                        if(pBuf != nullptr) {
                            FileCache::writeFile(strTarget, pBuf, nLength);
                            vecFiles[i] = strTarget;
                        } else {
                            vecFiles[i] = "";
                        }
                    } else {
                        vecFiles[i] = strTarget;
                    }
                }
            }
            if(!vecFiles[i].empty()) {
                char* result = nullptr;
                string mimeType = getMIMEType(vecFiles[i]);
                FileManagement_ErrCode errCode = OH_FileUri_GetUriFromPath(vecFiles[i].c_str(),vecFiles[i].length(), &result);
                if(errCode == ERR_OK) {
                    if(!strFiles.empty()) {
                        strFiles += ",";
                        strMimeTypes += ",";
                    }
                    strFiles += result;
                    strMimeTypes += mimeType;
                }
                if(result != nullptr) {
                    free(result);
                }
           }
        }
        cJSON_AddStringToObject(pJson, "files", strFiles.c_str());
        cJSON_AddStringToObject(pJson, "mimeTypes", strMimeTypes.c_str());
    }
    
    cJSON_AddStringToObject(pJson, "to", strTo.c_str());
    cJSON_AddStringToObject(pJson, "cc", strCc.c_str());
    cJSON_AddBoolToObject(pJson, "peek", isPeek);
    cJSON_AddStringToObject(pJson, "bcc", strBcc.c_str());
    char* pStr = cJSON_Print(pJson);
    strInfo = pStr;
    free(pStr);
    cJSON_Delete(pJson);
    return true;
}
   
bool SocialSharing::getSmsInfo(const string& phones, const string& strMessage, const string& strSubject, const string& strImage, string& strInfo)
{
    cJSON* pJson = cJSON_CreateObject();
    cJSON_AddStringToObject(pJson, "phones", phones.c_str());
    cJSON_AddStringToObject(pJson, "message", strMessage.c_str());
    cJSON_AddStringToObject(pJson, "subject", strSubject.c_str());
    string strUrl;
    if(strImage.find("http") == 0) { 
        string strFilePath;
        if(downloadFile(strImage, strFilePath)) {
            strUrl = strFilePath;
        } 
    }
    
    if(strImage.find("data:") == 0) {
        string strBase64Data = strImage.substr(strImage.find("base64")+7);
        if(!strBase64Data.empty()) {
            string strFileName = HttpUrl::generateMD5(strBase64Data)+FileCache::getImageType(strBase64Data);
            string strTarget = Application::g_databaseDir.substr(0, Application::g_databaseDir.find("database")-1)+"/base/"+strFileName;
            if(!FileCache::IsFile(strTarget, "")) {
                string str = FileCache::urlDecode(strBase64Data);
                int nLength = str.length();
                char* pBuf = CBase64::decode(str.c_str(), nLength);
                if(pBuf != nullptr) {
                    FileCache::writeFile(strTarget, pBuf, nLength);
                    strUrl = strTarget;
                } 
            } else {
                strUrl = strTarget;
            }
        }
    }
    if(!strUrl.empty()) {
        cJSON_AddStringToObject(pJson, "image", strUrl.c_str());
    }
    char* pStr = cJSON_Print(pJson);
    strInfo = pStr;
    free(pStr);
    cJSON_Delete(pJson);
    return true;   
}
   
string SocialSharing::getMIMEType(const string& fileName)
{
    string type = "*/*";
    int dotIndex = fileName.find_last_of(".");
    if (dotIndex == string::npos) {
      return type;
    }
    
    string end = fileName.substr(dotIndex+1);
    char * result = (char*)malloc(end.length()+1);
    if (result == NULL) return type;
    const char* str = end.c_str();
    for (int i = 0; str[i]; i++) {
        result[i] = tolower(str[i]);
    }
    result[strlen(str)] = '\0';
    auto it = m_mapMime.find(result);
    if(it != m_mapMime.end()) {
        type = it->second;
    }
    free(result);
    return type;
}

bool SocialSharing::downloadFile(const string& strSource, string& strFilePath)
{
    vector<SMemPage> vecMemBuf;
    ((CMemPool*)Application::g_memPool)->MallocPage(vecMemBuf, 1);
    if(vecMemBuf.size() < 1) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "FileTransfer", "((CMemPool*)Application::g_memPool)->MallocPage(vecMemBuf, 1) == NULL");
        return NULL;
    }
    int nBufSize = ((CMemPool*)Application::g_memPool)->GetPageSize();
    char* pBuf = vecMemBuf[0].m_point;
    
    string strExt = ".jpg";
    if(strSource.find_last_of(".") != string::npos) {
        strExt = strSource.substr(strSource.find_last_of("."));
    }
    string strFileName = HttpUrl::generateMD5(strSource) + strExt;
    string strTarget = Application::g_databaseDir.substr(0, Application::g_databaseDir.find("database")-1)+"/base/"+strFileName;
    if(FileCache::IsFile(strTarget, "")) {
        strFilePath = strTarget;
        return true;
    }
    bool isSuccess = download(strSource, strTarget, pBuf, nBufSize);
    ((CMemPool*)Application::g_memPool)->FreePage(vecMemBuf);
    if(isSuccess) {
        strFilePath = strTarget;
    }
    return isSuccess;
}

bool SocialSharing::download(const string& strSource, const string& strTarget, char* pBuf, const int nLength)
{
    //1，解析url
    string urlPath = strSource;
    string requestAddress = "";
    urlPath = urlPath.erase(0, urlPath.find_first_not_of(" "));
    urlPath = urlPath.erase(urlPath.find_last_not_of(" ") + 1);
    if(urlPath.find("//") != string::npos) {
        requestAddress = urlPath.substr(urlPath.find("//")+2);
    }
    
    //2,解析http/https协议类型
    int nPort = 0;
    bool isHttps = false;
    if(urlPath.find("https") == 0) {
        isHttps = true;
        nPort = 443;
    } else if(urlPath.find("http") == 0) {
        isHttps = false;
        nPort = 80;
    } else {
        return false;
    }
    
    //3解析域名修改请求地址
    string strDomainAndPort;
    string strDomain;
    if(urlPath.find("//") != string::npos) {
        strDomain = urlPath.substr(urlPath.find("//")+2);
        strDomainAndPort = strDomain;
        if(strDomain.find("/") != string::npos) {
            strDomain = strDomain.substr(0, strDomain.find("/"));
            strDomainAndPort = strDomain;
        }
        if(strDomain.find(":") != string::npos) {
            string strPort = strDomain.substr(strDomain.find(":")+1);
            strDomain = strDomain.substr(0, strDomain.find(":"));
            nPort = atoi(strPort.c_str());
        }    
        requestAddress = requestAddress.substr(strDomainAndPort.length());
    }
    
    
    string strRequest;
    strRequest = "GET " + requestAddress + " HTTP/1.1\r\n"; //GET %s HTTP/1.1\r\n
    
    vector<SMemPage> vecMemBuf;
    ((CMemPool*)Application::g_memPool)->MallocPage(vecMemBuf, 1);
    if(vecMemBuf.size() < 1) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "FileTransfer", "((CMemPool*)Application::g_memPool)->MallocPage(vecMemBuf, 1) == NULL");
        return false;
    }
    
    char* szBuf = vecMemBuf[0].m_point;
    if(nPort == 80 || nPort == 443)
        sprintf(szBuf, "Host:%s\r\n", strDomain.c_str());
    else
        sprintf(szBuf, "Host:%s:%d\r\n", strDomain.c_str(), nPort);
    strRequest += szBuf;
    
    sprintf(szBuf, "Connection:Keep-Alive\r\n");
    strRequest += szBuf;
    
    string strHttpUrl = isHttps?"https://"+strDomainAndPort:"http://"+strDomainAndPort;
    if(Application::g_cookieManage != NULL && !ARKWEB_MEMBER_MISSING(Application::g_cookieManage, existCookies)) {
        if(Application::g_cookieManage->existCookies(false)) {
            if(!ARKWEB_MEMBER_MISSING(Application::g_cookieManage, fetchCookieSync)) {
                char* pCookieValue = NULL;
                Application::g_cookieManage->fetchCookieSync(strHttpUrl.c_str(), false, true, &pCookieValue);
                if(pCookieValue != NULL && strlen(pCookieValue) > 0) {
                    string strCookies = pCookieValue;
                    string strCookie = "Set-Cookie:";
                    size_t pos;
                    while ((pos = strCookies.find(strCookie)) != std::string::npos) {
                        strCookies.erase(pos, strCookie.length());
                    }
                    sprintf(szBuf, "Cookie:%s\r\n", strCookies.c_str());
                    strRequest += szBuf;
                }
                if(pCookieValue != NULL) {
                    OH_ArkWeb_ReleaseString(pCookieValue);
                }    
            }
        }
    }
    
    sprintf(szBuf, "Keep-Alive:timeout=5, max=1000\r\n\r\n");
    strRequest += szBuf;
    ((CMemPool*)Application::g_memPool)->FreePage(vecMemBuf);
    
    ConnPoolManage* connPoolManage = (ConnPoolManage*)Application::g_connPoolManage;
    ConnPool* pool = connPoolManage->getConnPool(strDomain);
    if(pool == NULL) {
        return "";
    }
    
    string strFileName = strTarget;
    map<string, string>  mapRespHeaders;
    std::atomic<bool> isAbort{false};
    if(isHttps) {
        bool isClose = false;
        SSL* ssl = NULL;
        if(!pool->getSSL(&ssl, nPort)) {
            OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "FileTransfer", "pool->getSocket(&ssl) == false");
        }else if(!pool->sendWithTimeOut(ssl, strRequest, std::ref(isAbort))) {
            OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "FileTransfer", "pool->sendWithTimeOut(ssl, strRequest) == false");
        }else if(!pool->recvHttpWithTimeOut(ssl,  "GET", strFileName, mapRespHeaders, "", pBuf, nLength, isClose, std::ref(isAbort), nullptr)) {
            OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "FileTransfer", "pool->recvHttpWithTimeOut(ssl, strFileName, pMaxBuffer, nBufSize, isReconnect) == false");
        }
        pool->freeSocket(ssl, isClose);
    } else {
        bool isClose = false;
        int nSocket = -1;
        if(!pool->getSocket(nSocket, nPort)) {
            OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "FileTransfer", "pool->getSocket(nSocket) == false");
        }else if(!pool->sendWithTimeOut(nSocket, strRequest, std::ref(isAbort))) {
            OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "FileTransfer", "pool->sendWithTimeOut(nSocket, strRequest) == false");
        }else if(!pool->recvHttpWithTimeOut(nSocket,  "GET", strFileName, mapRespHeaders, "", pBuf, nLength, isClose, std::ref(isAbort), nullptr)) {
            OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_PRINT_DOMAIN, "FileTransfer", "pool->recvHttpWithTimeOut(nSocket, strFileName, pMaxBuffer, nBufSize, isReconnect) == false");
        }
        pool->freeSocket(nSocket, true);
    }
    
    if(!FileCache::IsFile(strFileName, "")) {
        return false;
    }
    return true;
}
